package cn.hj.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import cn.hj.domain.rebate.model.aggregate.BehaviorRebateAggregate;
import cn.hj.domain.rebate.model.entity.BehaviorRebateOrderEntity;
import cn.hj.domain.rebate.model.entity.TaskEntity;
import cn.hj.domain.rebate.model.valobj.BehaviorTypeVO;
import cn.hj.domain.rebate.model.valobj.DailyBehaviorRebateVO;
import cn.hj.domain.rebate.repository.IBehaviorRebateRepository;
import cn.hj.infrastructure.event.EventPublisher;
import cn.hj.infrastructure.persistent.dao.IDailyBehaviorRebateDao;
import cn.hj.infrastructure.persistent.dao.ITaskDao;
import cn.hj.infrastructure.persistent.dao.IUserBehaviorRebateOrderDao;
import cn.hj.infrastructure.persistent.po.DailyBehaviorRebate;
import cn.hj.infrastructure.persistent.po.Task;
import cn.hj.infrastructure.persistent.po.UserBehaviorRebateOrder;
import cn.hj.types.enums.ResponseCode;
import cn.hj.types.exception.AppException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@Primary
@Slf4j
public class BehaviorRebateRepository implements IBehaviorRebateRepository {

    @Resource
    private IDailyBehaviorRebateDao dailyBehaviorRebateDao;

    @Resource
    private IUserBehaviorRebateOrderDao userBehaviorRebateOrderDao;

    @Resource
    private ITaskDao taskDao;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private EventPublisher eventPublisher;

    @Resource
    private IDBRouterStrategy dbRouter;


    @Override
    public List<DailyBehaviorRebateVO> queryDailyBehaviorRebateConfig(BehaviorTypeVO behaviorTypeVO) {
        List<DailyBehaviorRebate> dailyBehaviorRebates = dailyBehaviorRebateDao.queryDailyBehaviorRebateByBehaviorType(behaviorTypeVO.getCode());
        return dailyBehaviorRebates.stream().map(dailyBehaviorRebate -> DailyBehaviorRebateVO.builder()
                .rebateConfig(dailyBehaviorRebate.getRebateConfig())
                .behaviorType(behaviorTypeVO.getCode())
                .rebateType(dailyBehaviorRebate.getRebateType())
                .rebateDesc(dailyBehaviorRebate.getRebateDesc())
                .build()).collect(Collectors.toList());

    }

    @Override
    public void saveUserRebateRecord(String userId, List<BehaviorRebateAggregate> behaviorRebateAggregates) {
        try {
            dbRouter.doRouter(userId);
            transactionTemplate.execute(status -> {
                try {
                    for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
                        BehaviorRebateOrderEntity behaviorRebateOrderEntity = behaviorRebateAggregate.getBehaviorRebateOrderEntity();
                        // 用户行为返利订单对象
                        UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
                        userBehaviorRebateOrder.setUserId(behaviorRebateOrderEntity.getUserId());
                        userBehaviorRebateOrder.setOrderId(behaviorRebateOrderEntity.getOrderId());
                        userBehaviorRebateOrder.setBehaviorType(behaviorRebateOrderEntity.getBehaviorType());
                        userBehaviorRebateOrder.setRebateDesc(behaviorRebateOrderEntity.getRebateDesc());
                        userBehaviorRebateOrder.setRebateType(behaviorRebateOrderEntity.getRebateType());
                        userBehaviorRebateOrder.setRebateConfig(behaviorRebateOrderEntity.getRebateConfig());
                        userBehaviorRebateOrder.setOutBusinessNo(behaviorRebateOrderEntity.getOutBusinessNo());
                        userBehaviorRebateOrder.setBizId(behaviorRebateOrderEntity.getBizId());
                        userBehaviorRebateOrderDao.insert(userBehaviorRebateOrder);

                        // 任务对象
                        TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
                        Task task = new Task();
                        task.setUserId(taskEntity.getUserId());
                        task.setTopic(taskEntity.getTopic());
                        task.setMessageId(taskEntity.getMessageId());
                        task.setMessage(JSON.toJSONString(taskEntity.getMessage()));
                        task.setState(taskEntity.getState().getCode());
                        taskDao.insert(task);
                    }
                    return 1;
                }catch (Exception e){
                    status.setRollbackOnly();
                    log.error("写入返利记录，唯一索引冲突 userId: {}", userId, e);
                    throw new AppException(ResponseCode.INDEX_OUT_OF_BOUNDS.getCode(), ResponseCode.INDEX_OUT_OF_BOUNDS.getInfo());
                }
            });

        }finally {
            dbRouter.clear();
        }

        // 同步发送MQ消息
        for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
            TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
            Task task = new Task();
            task.setUserId(taskEntity.getUserId());
            task.setMessageId(taskEntity.getMessageId());
            try {
                // 发送消息【在事务外执行，如果失败还有任务补偿】
                eventPublisher.publish(taskEntity.getTopic(), taskEntity.getMessage());
                // 更新数据库记录，task 任务表
                taskDao.updateTaskSendMessageCompleted(task);
            } catch (Exception e) {
                log.error("写入返利记录，发送MQ消息失败 userId: {} topic: {}", userId, task.getTopic());
                taskDao.updateTaskSendMessageFail(task);
            }
        }

    }

    @Override
    public List<BehaviorRebateOrderEntity>  queryOrderByOutBusinessNo(String userId, String outBusinessNo) {
        UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
        userBehaviorRebateOrder.setUserId(userId);
        userBehaviorRebateOrder.setOutBusinessNo(outBusinessNo);
        List<UserBehaviorRebateOrder> userBehaviorRebateOrders = userBehaviorRebateOrderDao.queryOrderByOutBusinessNo(userBehaviorRebateOrder);
        return userBehaviorRebateOrders.stream().map(
                userBehaviorRebateOrder1 -> BehaviorRebateOrderEntity.builder()
                        .orderId(userBehaviorRebateOrder1.getOrderId())
                        .userId(userId)
                        .outBusinessNo(outBusinessNo)
                        .bizId(userBehaviorRebateOrder1.getBizId())
                        .behaviorType(userBehaviorRebateOrder1.getBehaviorType())
                        .rebateConfig(userBehaviorRebateOrder1.getRebateConfig())
                        .rebateDesc(userBehaviorRebateOrder1.getRebateDesc())
                        .rebateType(userBehaviorRebateOrder1.getRebateType())
                        .build()
        ).collect(Collectors.toList());
    }
}
